﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Text;
using System.Web;

namespace Sharp
{
    public class Comet : Web, IHttpAsyncHandler
    {
        public delegate void ProcessReq(AsyncRequestState state);
        public ProcessReq Preq { get; set; }
        public AsyncRequest ar { get; set; }

        public Comet() { }

        public Comet(ProcessReq preq)
        {
            Preq = preq;
        }

        public void ProcessRequest(HttpContext ctx)
        {
            // not used
        }

        public bool IsReusable
        {
            get { return false; }
        }

        public IAsyncResult BeginProcessRequest(HttpContext context,
                                                AsyncCallback cb,
                                                object obj)
        {
            AsyncRequestState reqState =
                              new AsyncRequestState(context, cb, obj);
            ar = new AsyncRequest(reqState, Preq);
            ThreadStart ts = new ThreadStart(ar.ProcessRequest);
            Thread t = new Thread(ts);
            t.Start();

            return reqState;
        }

        public void EndProcessRequest(IAsyncResult ar)
        {
            // This will be called on the manually created thread in response to 
            // calling the ASP.NET AsyncCallback delegate once the request has
            // completed processing. The incoming IAsyncResult parameter will be 
            // a reference to the AsyncRequestState class, so the Context can be
            // accessed through that class. Note - you *cannot* access the 
            // current context using the HttpContext.Current property, as you are 
            // running on your own thread which has not been initialized with a 
            // context reference.
            AsyncRequestState ars = ar as AsyncRequestState;
            if (ars != null)
            {
                // here you could perform some cleanup, write something else to the
                // Response, or whatever else you need to do
            }
        }

        public class AsyncRequest
        {
            public AsyncRequestState asyncRequestState;
            public ProcessReq HandleRequest {get;set;}
            public String CacheID { get; set; }

            public void ProcessRequest()
            {
                if (HandleRequest == null)
                    ProcessRequestDefault();
                else
                    HandleRequest(asyncRequestState);
            }

            public AsyncRequest(AsyncRequestState ars, ProcessReq preq)
            {
                if (preq!=null)
                    HandleRequest = preq; 

                asyncRequestState = ars;
            }

            public void ProcessRequestDefault()
            {
            }
        }


        public class AsyncRequestState : IAsyncResult
        {
            public AsyncRequestState(HttpContext context,
                                     AsyncCallback cb,
                                     object extraData)
            {
                _context = context;
                _cb = cb;
                _extraData = extraData; 
            }

            public HttpContext _context;
            internal AsyncCallback _cb;
            internal object _extraData;
            private bool _isCompleted = false;
            private ManualResetEvent _callCompleteEvent = null;

            public void CompleteRequest()
            {
                _isCompleted = true;
                lock (this)
                {
                    if (_callCompleteEvent != null)
                        _callCompleteEvent.Set();
                }
                // if a callback was registered, invoke it now
                if (_cb != null)
                    _cb(this);
            }

            // IAsyncResult interface property implementations
            public object AsyncState
            { get { return (_extraData); } }
            public bool CompletedSynchronously
            { get { return (false); } }
            public bool IsCompleted
            { get { return (_isCompleted); } }
            public WaitHandle AsyncWaitHandle
            {
                get
                {
                    lock (this)
                    {
                        if (_callCompleteEvent == null)
                            _callCompleteEvent = new ManualResetEvent(false);

                        return _callCompleteEvent;
                    }
                }
            }
        }
    }
}
